#include "screen.h"

// 在源文件中定义全局变量
lv_disp_draw_buf_t draw_buf;
lv_color_t *buf = nullptr;
TFT_eSPI tft = TFT_eSPI();

// Logo buffer variables
static uint16_t* logoBuffer1 = nullptr;
static uint16_t* logoBuffer2 = nullptr;
static uint16_t* logoBufferPtr = nullptr;
static bool logoBufferSel = 0;

#if LV_USE_LOG != 0
void my_print(const char * buf)
{
    logf(buf);
    ConsoleInfo.flush();
}
#endif

void set_brightness(int _brightness, bool remenber){
   if (_brightness < 255 && _brightness > 5){
      analogWrite(PIN_BLK, _brightness);
      if (remenber) {brightness = _brightness;}
   } else if(_brightness >= 255) {
        digitalWrite(PIN_BLK, HIGH);
        if (remenber){brightness = _brightness;}
   } else if(_brightness <= 5) {
    analogWrite(PIN_BLK, 5); 
    if(remenber){brightness = _brightness;}
   }
}

void smooth_off(){
//    digitalWrite(PIN_BLK, LOW);
   for(int i=0; i<brightness; i++){
      set_brightness(i, false);
      delay(2);
   }
   digitalWrite(PIN_BLK, HIGH);
}

void smooth_on(){
    digitalWrite(PIN_BLK, HIGH);
//    analogWrite(PIN_BLK, brightness);
   for(int i=brightness; i>=0; i--){
      analogWrite(PIN_BLK, i);
      delay(2);
   }
   digitalWrite(PIN_BLK, LOW);
}

bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap){
  if ( y >= tft.height() ) return 0;
  if (logoBufferSel) logoBufferPtr = logoBuffer2;
  else logoBufferPtr = logoBuffer1;
  logoBufferSel = !logoBufferSel;
  tft.pushImageDMA(x, y, w, h, bitmap, logoBufferPtr);
  return 1;
}

void my_disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p){
    uint32_t w = ( area->x2 - area->x1 + 1 );
    uint32_t h = ( area->y2 - area->y1 + 1 );
    tft.startWrite();
    tft.setAddrWindow( area->x1, area->y1, w, h );
    tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
    tft.endWrite();
    lv_disp_flush_ready( disp_drv );
}
 
void render_logo(){
    // 动态分配内存
    logoBuffer1 = (uint16_t*)malloc(16 * 16 * sizeof(uint16_t));
    logoBuffer2 = (uint16_t*)malloc(16 * 16 * sizeof(uint16_t));

    if (logoBuffer1 == nullptr || logoBuffer2 == nullptr) {
        if (logoBuffer1) free(logoBuffer1);
        if (logoBuffer2) free(logoBuffer2);
        logoBuffer1 = nullptr;
        logoBuffer2 = nullptr;
        return;
    }
    
    tft.fillScreen(TFT_BLACK);
    TJpgDec.setJpgScale(1);
    TJpgDec.setCallback(tft_output);
    uint16_t w = 0, h = 0;
    TJpgDec.getJpgSize(&w, &h, logo, sizeof(logo));
    tft.startWrite();
    TJpgDec.drawJpg(0, 0, logo, sizeof(logo));
    tft.endWrite();
    
    // 释放内存
    if (logoBuffer1) free(logoBuffer1);
    if (logoBuffer2) free(logoBuffer2);
    logoBuffer1 = nullptr;
    logoBuffer2 = nullptr;
}

void screen_element_prepare(){ 
    tft.fillScreen(TFT_YELLOW);
}

void screen_init(){
    logln("Initializing screen...");
    if(io.pinMode(0, OUTPUT)){
      logln("PCA9557 IO0 setup Okay");
    }else{
      logln("PCA9557 IO0 setup Failed");
    }

    pinMode(PIN_BLK, OUTPUT);
    if (PIN_SCREEN_VDD != NOT_USE){pinMode(PIN_SCREEN_VDD, OUTPUT);}
    
    digitalWrite(PIN_BLK, HIGH);
    
    if (PIN_SCREEN_VDD != NOT_USE){digitalWrite(PIN_SCREEN_VDD, LOW);};
    lv_init();
    tft.init();
    tft.setRotation(1);
    tft.setSwapBytes(true);
    tft.initDMA();
    logln("[Display] Screen powerd on.");
    render_logo();
    delay(300);
    smooth_on();
    logf("[Display] Logo rendered");
    delay(500);
    smooth_off();
    
    #if LV_USE_LOG != 0
    lv_log_register_print_cb( my_print );
    #endif    
    // 动态分配缓冲区内存
    buf = (lv_color_t*)heap_caps_malloc(sizeof(lv_color_t) * UMEKO_LV_BUFFER_SIZE, MALLOC_CAP_DMA);
    if(buf == nullptr) {
        logln("[ERROR] Failed to allocate display buffer");
        return;
    }
    
    lv_disp_draw_buf_init( &draw_buf, buf, NULL, UMEKO_LV_BUFFER_SIZE);
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init( &disp_drv );
    disp_drv.hor_res = TFT_HEIGHT;
    disp_drv.ver_res = TFT_WIDTH;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.draw_buf = &draw_buf;
    
    lv_disp_drv_register( &disp_drv );
    logln("[Display] lvgl initialized");
    // smooth_on();
}

void screen_update(){
    delay(1000);
    tft.fillScreen(TFT_BLUE);
    delay(1000);
    tft.fillScreen(TFT_RED);
    delay(1000);
    tft.fillScreen(TFT_YELLOW);
    delay(1000);
    render_logo();
    logln("Screen looped.");
}

void screen_deinit() {
    if(buf != nullptr) {
        heap_caps_free(buf);
        buf = nullptr;
    }
}